//1、call
Function.prototype.sx_call = function(obj,...args){
    obj = obj || window
    //Symbol 是唯一的，防止重名key
    const fn = Symbol()
    obj[fn] = this
    //执行，返回执行值
    return obj[fn](...args)
}

const testobj = {
    name: '33',
    testFn(age,sex){
        console.log(`${this.name}${age}岁了,且性别为${sex}`)
    }
}

const testobj2 = {
    name: '333332222222'
}

// testobj.testFn.sx_call(testobj2,22,'女')

//2、apply
Function.prototype.sx_apply = function(obj,args){
    obj = obj || window
    const fn = Symbol()
    obj[fn] = this

    return obj[fn](...args)
}

// testobj.testFn.sx_apply(testobj2,[22,'女'])

/**
 * 1、apply和call的定义
 * apply和call就是改变当前对象的作用域，B能够访问A中的方法C，在这里我们称作B改变了A中this的指向，相当于将A对象中函数C的上下文修改为B
 * 官方的定义：
 * apply: 调用一个对象的一个方法，用另一个对象替换当前对象，例如：A.apply(B, arguments),即B对象调用A对象的方法
 * call:调用一个对象的一个方法，用另一个对象替换当前对象，例如：A.apply(B, args1, args2),即B对象调用A对象的方法
 * 从官方的定义我们可以看出apply和call的唯一区别在于，它们的参数不同，apply接受两个参数，第一个参数为要改变的原函数的上下文，第二个参数为替换原函数的参数，我们需要注意的
 * 是第一个参数必须是数组。call可以接收多个参数，第一个参数是要改变的原函数的上下文，第二个参数和以后的参数替换原函数的参数
 */




// 3、Function.prototype.bind
//难点：bind 是返回一个函数，而不是执行结果
//bind 返回的函数，拿来当作构造函数，该怎么处理

Function.prototype.sx_bind = function(obj, ...args){
    obj = obj || window
    let fn = Symbol()
    obj[fn] = this
    return function (...innerArgs){
        let finalArgs = [...args,...innerArgs]
        return obj[fn](...finalArgs)
    }
}

var result = testobj.testFn.bind(testobj2,22,'女')
result(34,'男')
var result1 = testobj.testFn.sx_bind(testobj2,22)
result1('女')


function  add(a,b) {
    return a + b
}

let res = add.bind(this,1,2)
console.log(res())
let res1 = res.bind(this,3,4)
console.log(res1())

/**bind作用
 * bind()方法主要是将函数绑定到某个对象，bind()会创建一个函数，函数体内的this对象的值会被绑定到传入bind()中的第一个参数的值，
 * 例如f.bind(obj)，实际上可以理解为obj.f,这时f函数体内的this自然指向的是obj
 */